/**
*  \file random.c
*
*  \brief
*
*  \author Michael J. Hohmann  <michael.hohmann@linde-mh.de>
*
*
*/

/*===============================================[ private includes  ]================================================*/
#include "random.h"
#include "../assertor/assertor.h"
#include "../pal/pal_mem.h"

/*===============================================[ private defines   ]================================================*/

/*===============================================[ private datatypes ]================================================*/

/** Private variables */
struct random_private
{
   struct random_obj default_obj; /**<  */
};

/*===============================================[ private variables ]================================================*/
static struct random_private random;

/*===============================================[ private functions ]================================================*/
static U8 random_generator( struct random_obj *me );

/*================================================[ inline functions ]================================================*/

/*================================================[ public functions ]================================================*/

RC random_construct( struct random_obj *me, U32 seed, random_entropy_func_t entropy_src )
{	
   if( NIL != me )
   {
      pal_memzero( me, sizeof *me );
   }

   if( NIL == me )
   {
      me = &random.default_obj;
   }

   me->seed=seed;
   me->entropy =entropy_src;

   return RC_SUCCESS;
}

U8 random_generator_u8( struct random_obj *me )
{
   U8 rv=0;
   random_generator_set(me, &rv, sizeof(rv) );
   return rv;
}

S8 random_generator_s8( struct random_obj *me )
{
   S8 rv=0;
   random_generator_set(me, &rv, sizeof(rv) );
   return rv;
}

U16 random_generator_u16( struct random_obj *me )
{
   U16 rv=0;
   random_generator_set(me, &rv, sizeof(rv) );
   return rv;
}

S16 random_generator_s16( struct random_obj *me )
{
   S16 rv=0;
   random_generator_set(me, &rv, sizeof(rv) );
   return rv;
}

U32 random_generator_u32( struct random_obj *me )
{
   U32 rv=0;
   random_generator_set(me, &rv, sizeof(rv) );
   return rv;
}

S32 random_generator_s32( struct random_obj *me )
{
   S32 rv=0;
   random_generator_set(me, &rv, sizeof(rv) );
   return rv;
}

U8 random_u8( void )
{
   return random_generator_u8( NIL);
}

S8 random_s8( void )
{
   return random_generator_s8( NIL );
}

U16 random_u16( void )
{
   return random_generator_u16( NIL );
}

S16 random_s16( void )
{
   return random_generator_s16( NIL );
}

U32 random_u32( void )
{
   return random_generator_u32( NIL );
}

S32 random_s32( void )
{
   return random_generator_s32( NIL );
}

void random_generator_set( struct random_obj *me, void *dest, pal_size_t size )
{
   U8 *d=dest;

   if( NIL == me )
   {
      me=&random.default_obj;
   }

   while(size--)
   {
      *d++= random_generator(me);
   }
}

void random_set( void *dest, pal_size_t size )
{
   random_generator_set( NIL, dest, size );
}

/*===============================================[ private functions ]================================================*/
/** Pseudo random number algorithm
*
*
*
*/
static U8 random_generator( struct random_obj *me )
{
   if( NIL == me )
   {
      me = &random.default_obj;
   }

   me->seed = me->seed * U32_CONST(1103515245) + U32_CONST(12345);

   if( NIL != me->entropy )
   {
      U32 more_entropy[16]; /* this array is uninitialized on purpose to use the entropy on the stack */
      me->seed ^= more_entropy[(me->seed>>0) & 0x0F];
      me->seed ^= more_entropy[(me->seed>>8) & 0x0F];
      me->seed ^= me->entropy();
   }
   return (U8)((me->seed>>5) & 0xFF);
}


/***********************************************************************************************************************
*                             Copyright 2020 Linde Material Handling. All rights reserved.                             *
***********************************************************************************************************************/
